package com.xucron.hgmonitor

import java.io.File

import scala.sys.process.Process
import scala.sys.process.ProcessLogger
import com.xucron.hgmonitor.data.Repository
import com.xucron.hgmonitor.data.Settings
import scala.actors.Actor

case class GetIncomingCount(actor: Actor, repo: Repository)
case class GetOutgoingCount(actor: Actor, repo: Repository)
case class GetChangeCount(actor: Actor, repo: Repository)

/**
 * Handles all interaction with the Mercurial executable.
 */
class Hg(settings: Settings) extends Actor{
  
  def act() = {
    
    loop {
      react {
        case GetIncomingCount(actor, repo) => {
          actor ! getIncomingCount(repo)
        }
        
        case GetOutgoingCount(actor, repo) => {
          actor ! getOutgoingCount(repo)
        }
        
        case GetChangeCount(actor, repo) => {
          actor ! getChangeCount(repo)
        }
        
      }
      
    }
  }
  
  /**
   * @param repo the repository to be checked.
   * @return the count for the number of incoming changesets.
   */
  def getIncomingCount(repo: Repository): Int = {
    var command = "in"
    if(!settings.showCount) command += " -l 1"
    countInOut(execCommand(command, new File(repo.path))._1)
  }

  /**
   * @param repo the repository to be checked.
   * @return the count for the number of outgoing changesets.
   */
  def getOutgoingCount(repo: Repository): Int = {
    var command = "out"
    if(!settings.showCount) command += " -l 1"  
    countInOut(execCommand(command, new File(repo.path))._1)
  }

  /**
   * @param repo the repository to be checked.
   * @return the count for the number of non committed changes.
   */
  def getChangeCount(repo: Repository): Int = {
    countChanges(execCommand("st", new File(repo.path))._1)
  }

  def execCommand(command: String, dir: File): (List[String], List[String], Int) = {

    val process = Process(settings.hgPath + " " + command, dir)

    var out = List[String]()
    var err = List[String]()

    val exit = process ! ProcessLogger((s) => out ::= s, (s) => err ::= s)

    (out.reverse, err.reverse, exit)

  }

  private def countInOut(output: List[String]): Int = {
    if(output.size == 0 || output(0).startsWith("abort:")) return 0
    var count = 0;    
    for (s <- output) if(s.startsWith("changeset:")) {count += 1}
    count
  }

  private def countChanges(output: List[String]): Int = {
    if(output.size == 0 || output(0).startsWith("abort:")) return 0
    var count = 0;
    val flags = List[Char]('?','!','A','M','R')
    for (s <- output) if(!s.startsWith("abort:")) if(flags.contains(s.charAt(0))) {count += 1}
    count
  }

}